package com.android.settings.audio.peq.peq.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;


import com.android.settings.R;
import com.android.settings.audio.peq.skin.SkinManager;
import com.android.settings.audio.peq.util.GetSize;
import com.android.settings.audio.peq.util.Util;

import java.util.Comparator;
import java.util.List;

/**
 * 
 * @author mai
 * 
 */
public class BezierCurveChart extends View {
	public static class Point {
		public static final Comparator<Point> X_COMPARATOR = new Comparator<Point>() {
			@Override
			public int compare(Point lhs, Point rhs) {
				return (int) (lhs.x * 1000 - rhs.x * 1000);
			}
		};

		public float x;
		public float y;

		public Point(float x, float y) {
			this.x = x;
			this.y = y;
		}

		public Point() {
		}

		@Override
		public String toString() {
			return "(" + x + ", " + y + ")";
		}
	}

	private static final float CURVE_LINE_WIDTH = 1f;
	private static final float HALF_TIP_HEIGHT = 16;
	private static final String TAG = BezierCurveChart.class.getSimpleName();

	private Point[] adjustedPoints;
	private Paint borderPaint = new Paint();
	private Paint chartBgPaint = new Paint();
	// The rect of chart, x labels on the bottom are not included
	private Rect chartRect = new Rect();
	private Paint curvePaint = new Paint();
	private Path curvePath = new Path();
	// private Paint fillPaint = new Paint();
	private Path fillPath = new Path();
	private Paint gridPaint = new Paint();
	private Paint labelPaint = new Paint();
	private String[] labels,defaultValues;
	private float maxY;
	private List<Point> originalList;
	private float scaleY;
	private Rect textBounds = new Rect();
	// private Paint tipLinePaint = new Paint();
	// private Paint tipPaint = new Paint();
	private Rect tipRect = new Rect();
	private RectF tipRectF = new RectF();
	private String tipText = "1111";
	private Paint tipTextPaint = new Paint();
//	private Bitmap backgoundBitmap;

	{
		borderPaint.setColor(Color.WHITE);
		borderPaint.setStyle(Paint.Style.STROKE);
		borderPaint.setStrokeCap(Paint.Cap.SQUARE);
		borderPaint.setStrokeWidth(4.0f);
		borderPaint.setAntiAlias(true);

		// EQ图形曲线
		curvePaint.setStyle(Paint.Style.STROKE);
		curvePaint.setStrokeCap(Paint.Cap.ROUND);
		curvePaint.setStrokeWidth(GetSize.dip2px(getContext(), CURVE_LINE_WIDTH));
		curvePaint.setColor(getResources().getColor(getEqColor()));
		curvePaint.setAntiAlias(true);
//		curvePaint.setAlpha(200);

		// fillPaint.setStyle(Paint.Style.FILL);
		// fillPaint.setColor(Color.rgb(0x00, 0xd2, 0xff));
		// fillPaint.setAlpha(170);
		// fillPaint.setAntiAlias(true);
		// �����
		chartBgPaint.setStyle(Paint.Style.FILL);
		chartBgPaint.setColor(getResources().getColor(R.color.peq_black_overlay));
		chartBgPaint.setAlpha(50);
		chartBgPaint.setAntiAlias(true);
		// ����
		gridPaint.setStyle(Paint.Style.STROKE);
		gridPaint.setColor(Color.argb(0x92, 0xD0, 0xD0, 0xD0));
		gridPaint.setAntiAlias(true);
		gridPaint.setStrokeWidth(0.3f);
//		gridPaint.setAlpha(100);

		// tipLinePaint.setStyle(Paint.Style.STROKE);
		// tipLinePaint.setStrokeCap(Paint.Cap.SQUARE);
		// tipLinePaint.setStrokeWidth(1.5f);
		// tipLinePaint.setColor(Color.rgb(0x00, 0x89, 0xd8));
		// tipLinePaint.setAntiAlias(true);
		// tipLinePaint.setAlpha(220);
		//
		// tipPaint.setStyle(Paint.Style.FILL);
		// tipPaint.setColor(Color.rgb(0x00, 0x89, 0xd8));
		// tipPaint.setAntiAlias(true);

		tipTextPaint.setColor(getResources().getColor(R.color.peq_white));
		tipTextPaint.setTextSize(GetSize.dip2px(getContext(), (float) 10));
		tipTextPaint.setAntiAlias(true);

		//EQ数值实时标识
		labelPaint.setColor(getResources().getColor(getPrimaryText()));
		labelPaint.setTextSize(GetSize.dip2px(getContext(), (float) 8.5));
		labelPaint.setAntiAlias(true);
	}

	public BezierCurveChart(Context context) {
		super(context);

	}

	public BezierCurveChart(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public void setLayoutParm(int width) {
		width = GetSize.dip2px(getContext(), width);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width,
				ViewGroup.LayoutParams.MATCH_PARENT);
		setLayoutParams(params);
	}

	/**
	 * 
	 * scale
	 */
	private void adjustPoints(int chartWidth, int chartHeight) {
		maxY = 68;
		// find max y coodinate
		/*
		 * for (Point p : originalList) { if (p.y > maxY) { maxY = p.y; } }
		 */

		// Y coodinate sacle
		scaleY = chartHeight / maxY;

		float axesSpan = originalList.get(originalList.size() - 1).x
				- originalList.get(0).x;
		float startX = originalList.get(0).x;

		for (int i = 0; i < originalList.size(); i++) {
			Point p = originalList.get(i);

			Point newPoint = new Point();
			newPoint.x = (p.x - startX) * chartWidth / axesSpan
					+ chartRect.left;

			newPoint.y = p.y * scaleY;
			newPoint.y = chartHeight - newPoint.y;
			if (i>=adjustedPoints.length){
				return;
			}
			adjustedPoints[i] = newPoint;

		}
	}

	private void buildPath(Path path) {
		// Important!
		path.reset();

		path.moveTo(adjustedPoints[0].x, adjustedPoints[0].y);
		int pointSize = adjustedPoints.length;

		for (int i = 0; i < adjustedPoints.length - 1; i++) {
			float pointX = (adjustedPoints[i].x + adjustedPoints[i + 1].x) / 2;
			float pointY = (adjustedPoints[i].y + adjustedPoints[i + 1].y) / 2;

			float controlX = adjustedPoints[i].x;
			float controlY = adjustedPoints[i].y;

			path.quadTo(controlX, controlY, pointX, pointY);

		}

		path.quadTo(adjustedPoints[pointSize - 1].x,
				adjustedPoints[pointSize - 1].y,
				adjustedPoints[pointSize - 1].x,
				adjustedPoints[pointSize - 1].y);
	}

	private void drawCurve(Canvas canvas, float width, float height) {
		buildPath(curvePath);
		// buildPath(fillPath);
		//
		// fillPath.lineTo(chartRect.right, chartRect.bottom);
		// fillPath.lineTo(chartRect.left, chartRect.bottom);
		// fillPath.lineTo(chartRect.left, adjustedPoints[0].y);
		// fillPath.close();
		//
		// canvas.drawPath(fillPath, fillPaint);
		canvas.drawPath(curvePath, curvePaint);
	}

	/**
	 * draw ���
	 * 
	 * @param canvas
	 * @param width
	 */
	private void drawGrid(Canvas canvas, int width) {


		int gridCount = labels.length - 1;
		float part = (float) width / gridCount;

		for (int i = 1; i < gridCount; i++) {
			float x = chartRect.left + part * i;
			canvas.drawLine(x, chartRect.top, x, chartRect.bottom, gridPaint);
		}
		float y=chartRect.top+part;
		while(y<chartRect.bottom){
			
			canvas.drawLine(chartRect.left, y, chartRect.right, y, gridPaint);

			y=y+part;
		}
	}

	/**
	 * draw
	 * 
	 * @param canvas
	 * 
	 * 
	 * @param width
	 */
	private void drawscrollline(Point[] ps, Canvas canvas, Paint paint) {
		Point startp = new Point();
		Point endp = new Point();
		for (int i = 0; i < ps.length - 1; i++) {
			startp = ps[i];
			endp = ps[i + 1];
			int wt = (int) ((startp.x + endp.x) / 2);
			Point p3 = new Point();
			Point p4 = new Point();
			p3.y = startp.y;
			p3.x = wt;
			p4.y = endp.y;
			p4.x = wt;

			Path path = new Path();
			path.moveTo(startp.x, startp.y);
			path.cubicTo(p3.x, p3.y, p4.x, p4.y, endp.x, endp.y);
			canvas.drawPath(path, paint);

		}
	}

	/**
	 * Draw labels on the bottom
	 * 
	 * @param canvas
	 */
	private void drawLabels(Canvas canvas) {

		int width = chartRect.right - chartRect.left;

		float labelY = chartRect.bottom-GetSize.dip2px(getContext(), 3);
		float part = (float) width / (labels.length - 1);

//		for (int i = 0; i < defaultValues.length; i++) {
//			String s = defaultValues[i];
//			float centerX = chartRect.left + part * i;
//			float labelWidth = getTextWidth(labelPaint, s);
//			float labelX;
//			if (i == 0) {
//				labelX = chartRect.left+GetSize.dip2px(getContext(), 2)+(getTextWidth(labelPaint, labels[i])-getTextWidth(labelPaint, s))/2;
//			} else if (i == labels.length - 1) {
//				labelX = chartRect.right - labelWidth-GetSize.dip2px(getContext(), 2);
//			} else {
//				labelX = centerX - labelWidth / 2+(getTextWidth(labelPaint, labels[i])-getTextWidth(labelPaint, s))/2;
//			}
//			canvas.drawText(s, labelX, labelY, labelPaint);
//		}

		chartRect.bottom = (int) (chartRect.bottom - getTextHeight(labelPaint) * 1.2);
		float labelY2 = chartRect.bottom-2*GetSize.dip2px(getContext(), 3);

		for (int i = 0; i < labels.length; i++) {
			String s = labels[i];
			float centerX = chartRect.left + part * i;
			float labelWidth = getTextWidth(labelPaint, s);
			float labelX;
			if (i == 0) {
				labelX = chartRect.left+GetSize.dip2px(getContext(), 2);
			} else if (i == labels.length - 1) {
				labelX = chartRect.right - labelWidth-GetSize.dip2px(getContext(), 2);
			} else {
				labelX = centerX - labelWidth / 2;
			}
			canvas.drawText(s, labelX, labelY, labelPaint);
		}

		chartRect.bottom = (int) (chartRect.bottom - getTextHeight(labelPaint) * 2);
//		chartRect.left=(int) (chartRect.left+getTextHeight(labelPaint) * 1.2);
	}

	/**
	 * Draw tip on the middle of the chart
	 * 
	 * @param canvas
	 * @param width
	 * @param height
	 */
	// private void drawTip(Canvas canvas, float width, float height) {
	//
	// // float totalHeight = 0;
	// // for (Point p : adjustedPoints) {
	// // totalHeight += p.y;
	// // }
	// //
	// // float tipLineY = totalHeight / adjustedPoints.length;
	// //
	// // if (tipLineY + HALF_TIP_HEIGHT >= chartRect.bottom) {
	// // tipLineY = chartRect.bottom - HALF_TIP_HEIGHT - 4;
	// // }
	// //
	// // String text = tipText;
	// // tipTextPaint.getTextBounds(text, 0, 1, textBounds);
	// //
	// // float centerX = chartRect.left + width / 2;
	// // float textWidth = getTextWidth(tipTextPaint, text);
	// //
	// // tipRect.left = (int) (centerX - textWidth / 2 - 23);
	// // tipRect.right = (int) (centerX + textWidth / 2 + 23);
	// // tipRect.top = (int) (tipLineY - HALF_TIP_HEIGHT);
	// // tipRect.bottom = (int) (tipLineY + HALF_TIP_HEIGHT);
	// //
	// // tipRectF.set(tipRect);
	// //
	// // float textX = centerX - textWidth / 2;
	// // int textHeight = textBounds.bottom - textBounds.top;
	// //
	// // float textY = tipLineY + textHeight / (float) 2 - 3;
	// //
	// // canvas.drawLine(chartRect.left, tipLineY, chartRect.right, tipLineY,
	// // tipLinePaint);
	// // canvas.drawRoundRect(tipRectF, HALF_TIP_HEIGHT, HALF_TIP_HEIGHT,
	// // tipPaint);
	// // canvas.drawText(text, textX, textY, tipTextPaint);
	// }

	private void drawEqText(Canvas canvas) {

		canvas.drawText(tipText, 20, (float) (chartRect.top +getTextHeight(tipTextPaint)*1.2), tipTextPaint);
	}

	public Paint getBorderPaint() {
		return borderPaint;
	}

	public Paint getChartBgPaint() {
		return chartBgPaint;
	}

	public Paint getCurvePaint() {
		return curvePaint;
	}

	// public Paint getFillPaint() {
	// return fillPaint;
	// }

	public Paint getGridPaint() {
		return gridPaint;
	}

	public Paint getLabelPaint() {
		return labelPaint;
	}

	public float getTextHeight(Paint textPaint) {
		FontMetrics fm = textPaint.getFontMetrics();
		return (float) Math.ceil(fm.descent - fm.ascent) - 2;
	}

	/**
	 * 
	 * @param textPaint
	 * @param text
	 * @return textwidth
	 */
	public float getTextWidth(Paint textPaint, String text) {
		
		return textPaint.measureText(text);

	}

	//
	// public Paint getTipLinePaint() {
	// return tipLinePaint;
	// }
	//
	// public Paint getTipPaint() {
	// return tipPaint;
	// }

	public Paint getTipTextPaint() {
		return tipTextPaint;
	}

	public void setData(List<Point> originalList) {
		this.originalList = originalList;
		adjustedPoints = new Point[originalList.size()];
		super.invalidate();
	}

	public void init(List<Point> originalList, String[] labels, String tipText) {
		this.originalList = originalList;
		this.labels = labels;
		if (this.labels == null) {
			this.labels = new String[originalList.size()];
			for (int i = 0, n = this.labels.length; i < n; ++i) {
				this.labels[i] = "";
			}
		}
		this.tipText = tipText;
		adjustedPoints = new Point[originalList.size()];
	
		super.invalidate();
	}

	public void init(List<Point> originalList, String[] labels,String[] defaultValue, String tipText) {
		this.originalList = originalList;
		this.labels = labels;
		this.tipText = tipText;
		defaultValues=defaultValue;
		adjustedPoints = new Point[originalList.size()];
		super.invalidate();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		getDrawingRect(chartRect);
		
//		canvas.drawRect(chartRect, chartBgPaint); //  background

//		Log.d(TAG, chartRect.toString());
	//	canvas.drawBitmap(backgoundBitmap, 0, 0, borderPaint);
		if (originalList != null) {
			drawLabels(canvas);
			int chartHeight = chartRect.bottom - chartRect.top;
			int chartWidth = chartRect.right - chartRect.left;
			try {
				adjustPoints(chartWidth, chartHeight);
				drawGrid(canvas, chartWidth);

				if (tipText != null) {
//				drawEqText(canvas);
				}
//			canvas.drawRect(chartRect, borderPaint);
				drawscrollline(adjustedPoints, canvas, curvePaint);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void setBorderPaint(Paint borderPaint) {
		this.borderPaint = borderPaint;
	}

	public void setChartBgPaint(Paint chartBgPaint) {
		this.chartBgPaint = chartBgPaint;
	}

	public void setCurvePaint(Paint curvePaint) {
		this.curvePaint = curvePaint;
	}

	// public void setFillPaint(Paint fillPaint) {
	// this.fillPaint = fillPaint;
	// }

	public void setGridPaint(Paint gridPaint) {
		this.gridPaint = gridPaint;
	}

	public void setLabelPaint(Paint labelPaint) {
		this.labelPaint = labelPaint;
	}

	// public void setTipLinePaint(Paint tipLinePaint) {
	// this.tipLinePaint = tipLinePaint;
	// }
	//
	// public void setTipPaint(Paint tipPaint) {
	// this.tipPaint = tipPaint;
	// }

	public void setTipTextPaint(Paint tipTextPaint) {
		this.tipTextPaint = tipTextPaint;
	}

	private int getPrimaryText(){
		if (Util.checkAppIsProductCAYIN()){
			return R.color.peq_item_primary_text;
		}
		if (SkinManager.get().getThemeMode()==SkinManager.GREEN_MODE){
			return R.color.peq_white_01;
		}else if (SkinManager.get().getThemeMode()==SkinManager.BLACK_MODE){
			return R.color.peq_white_02;
		}else {
			return R.color.peq_black_01;
		}
	}

	private int getEqColor(){
		if (Util.checkAppIsProductCAYIN()){
			return R.color.peq_skin_item_select;
		}
		if (SkinManager.get().getThemeMode()==SkinManager.GREEN_MODE){
			return R.color.peq_white_01;
		}else if (SkinManager.get().getThemeMode()==SkinManager.BLACK_MODE){
			return R.color.peq_white_02;
		}else {
			return R.color.peq_black_01;
		}
	}
}
